#pragma once
#include "src/core/SkChecksum.h"
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cstring>

#define HASH_UNIQUE_ID [](){ static char id; return (uint64_t)&id; }()

class DrawingHash {
public:
    DrawingHash(uint64_t seed = 0) { fSeed = seed; }
    
    template <typename T> inline void push(const T &value) { pushBytes(&value, sizeof(T)); }

    template <typename T> inline void pushArray(const T *values, size_t count) { pushBytes(values, sizeof(T) * count); }

    inline uint64_t digest() const {
        return fSeed;
    }

    static inline uint64_t RunningUniqueId() {
        static std::atomic<uint64_t> last{0};
        uint64_t now = NowNs();
        uint64_t prev = last.load(std::memory_order_relaxed);
        while (true) {
            uint64_t next = now > prev ? now : prev + 1;
            if (last.compare_exchange_weak(prev, next, std::memory_order_relaxed)) {
                return next;
            }
        }
    }
    
private:
    static inline uint64_t NowNs() {
        struct timespec ts;
        clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
        return uint64_t(ts.tv_sec) * 1000000000ull + ts.tv_nsec;
    }
    
    uint64_t fSeed = 0;

    inline void pushBytes(const void *ptr, size_t len) {
        if (len > 0 && ptr != nullptr) {
            fSeed = SkChecksum::Hash64(ptr, len, fSeed);
        }
    }
};
